#pragma once
#include "GnSystem.h"

#define NI_NUM_LIBRARIES 16

class GNSYSTEM_ENTRY GnEngineBegingManager
{
public:
	GnEngineBegingManager(void);
	~GnEngineBegingManager(void);

	static void Startup();
	static void Shutdown();


	typedef void (*StartupFunction)(void);
	typedef void (*ShutdownFunction)(void);

	static void AddLibrary(const gchar* libName, const gchar* dependencie,
		StartupFunction funcStartup, ShutdownFunction funcShutdown);
	static void RemoveLibrary(const gchar* pcLibName);
	static void ProcessAccumulatedLibraries();

private:
	struct LibraryNode
	{
		/// The name of the library.
		const gchar* m_pcName;

		/// A white-space separated list of library names on which this
		/// library depends.
		const gchar* m_pcDependsOn;

		/// The initialization function.
		StartupFunction m_pfnInitFunction;

		/// The shutdown function.
		ShutdownFunction m_pfnShutdownFunction;

		/// Edges in the graph that is used to find an initialization order.
		guint8* m_puiDependencies;
		guint8 m_uiNumDependencies;
		guint8 m_uiMaxDependencies;

		/// The index into the array of all libraries
		guint8 m_uiIndex;
	};


	static bool HasDependents(const guint8 uiLibIndex);
	static bool DependenciesInitialized(const guint8 uiLibIndex);
	static bool ComputeProcessOrder();
	static bool ConstructDependencyGraph(const guint8 uiLibIndex, guint8* auiUnvisited,
		guint8& uiNumUnvisited, guint8* auiDependencyFree, guint8& uiNumDependencyFree);
	static void AddDependency(const guint8 uiLibIndex, const guint8 uiDependentIndex);
	static void RemoveDependencies(const guint8 uiLibIndex, guint8* auiUnvisited,
		guint8& uiNumUnvisited, guint8* auiDependencyFree, guint8& uiNumDependencyFree);

	static LibraryNode ms_akLibraries[NI_NUM_LIBRARIES];
	static guint8 ms_auiProcessOrder[NI_NUM_LIBRARIES];
	static guint8 ms_uiNumLibraries;
	static guint8 ms_uiNumInitializedLibraries;
	static bool ms_bAutoCreatedInitOptions;
	static bool ms_bInitialized;
};


#define GnStartup GnEngineBegingManager::Startup
#define GnShutdown GnEngineBegingManager::Shutdown